package org.skyui.beanmanagers;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.skyui.accesscontrol.HumanAuthenticator;
import org.skyui.annotations.SkyBean;
import org.skyui.beans.AbstractBean;
import org.skyui.beans.OrganizationBean;
import org.skyui.jpa.JPAManager;

import com.baycrypt.server.beans.commands.AbstractCommandBean;
import com.baycrypt.server.beans.commands.DeviceLockCommandBean;
import com.baycrypt.server.beans.commands.DeviceUnlockCommandBean;
import com.baycrypt.server.beans.commands.WLANRotateKeyCommandBean;
import com.baycrypt.server.beans.devices.DeviceBean;
import com.baycrypt.server.beans.networks.WLANBean;
import com.baycrypt.server.beans.people.AccessCardBean;
import com.baycrypt.server.beans.people.AccessCardSheetBean;
import com.baycrypt.server.beans.people.OneTimeLoginBean;
import com.baycrypt.server.beans.people.UserBean;
import com.baycrypt.server.core.CommandProcessor;
import com.baycrypt.vaadinui.VaadinUIApplication;

public class BeanSetManager extends AbstractBeanManager {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3206218578366003234L;
	protected Class beanTemplateClass;

	protected BeanSetManager(Class beanClass) {
		this(beanClass, null);
	}

	protected BeanSetManager(Class beanClass, Class[] classes) {

		super(beanClass);
		if (classes != null) {
			for (Class cl : classes)
				this.addCommandManager(cl);
		}
			this.beanTemplateClass = beanClass;
	}

	public Set getRefreshedBeans() {
		Set s = new HashSet(JPAManager.readBeansFromStorage(this.beanClass,
				getOrganization()));

		return s;
	}
	
	public List getRefreshedBeansAsList() {
		return JPAManager.readBeansFromStorage(this.beanClass,
				getOrganization());
	}

	public final AbstractBean getBeanByPrimaryAttribute(String value) {
		for (Object bean : getRefreshedBeans()) {
			if (((AbstractBean) bean).getPrimaryAttribute().equals(value))
				return (AbstractBean) bean;
		}
		return null;
	}

	public final AbstractBean getBeanById(String value) {
		for (Object bean : getRefreshedBeans()) {
			if (((AbstractBean) bean).getId().equals(value))
				return (AbstractBean) bean;
		}
		return null;
	}

	public static Set getRefreshedBeans(Class beanClass,
			OrganizationBean organization) {
		return getManager(beanClass, organization).getRefreshedBeans();
	}

	public static synchronized BeanSetManager getManagerFromUserSession(
			Class beanClass) {
		return getManager(beanClass, HumanAuthenticator.getOrganization());
	}

	public static BeanSetManager getManager(Class beanClass,
			OrganizationBean organization) {

		BeanSetManager manager;

		if (AbstractCommandBean.class.isAssignableFrom(beanClass)) {
			manager = new CommandManager(beanClass);
		} else {
			Class[] commandClasses = null;
			SkyBean a = (SkyBean) beanClass.getAnnotation(SkyBean.class);
			if (a != null) {
				commandClasses = a.commandClasses();
			}
			if (commandClasses != null && commandClasses.length > 0
					&& organization != null)
				manager = new BeanSetManager(beanClass, commandClasses);
			else {
				manager = new BeanSetManager(beanClass);
			}
		}
		manager.setOrganization(organization);
		return manager;
	}

	public AbstractBean createTemplate() {
		try {
		    
			AbstractBean template = AbstractBean.createTemplate(this.beanTemplateClass);
			if (!beanTemplateClass.equals(OrganizationBean.class))
				template.setOrganization(VaadinUIApplication.getInstance()
						.getOrganization());
			return template;
		} catch (Exception e) {
			throw new Error("Could not find template class", e);
		}
	}

	public AbstractBean createBeanFromTemplate(AbstractBean t) {
		if (t instanceof DeviceLockCommandBean) {
			DeviceBean device = (DeviceBean) ((DeviceLockCommandBean) t)
					.getTarget();

			return createBeanFromTemplate(t, device);
		}
		if (t instanceof DeviceUnlockCommandBean) {
			DeviceBean device = (DeviceBean) ((DeviceUnlockCommandBean) t)
					.getTarget();
			return createBeanFromTemplate(t, device);
		}

		return createBeanFromTemplate(t, null);
	}

	public final AbstractBean createBeanFromTemplate(AbstractBean t,
			DeviceBean device) {
		AbstractBean bean = cloneBeanFromTemplate(t);

		if (bean instanceof AbstractCommandBean) {
			if (device == null)
				((AbstractCommandBean) bean).initCommandStates();
			else
				((AbstractCommandBean) bean).initCommandState(device);
		}

		bean.createPersist();

		if (bean instanceof AbstractCommandBean) {
			CommandProcessor.processNewCommandStates();
		}

		return bean;
	}

	public AbstractBean cloneBeanFromTemplate(AbstractBean t) {                         
	                t.setCreationTime(new Date());
			if (OrganizationBean.class.equals(t.getClass())) {
				t.setOrganization((OrganizationBean) t);
			}
			t.runOnCreateFromTemplate();
			t.setTemplate(false);
			return t;
	}

}
